﻿
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace StateManager
{
    internal class SEngine : IDisposable
    {
        Thread _thread;
        bool _auto;
        internal bool Auto
        {
            get { return _auto; }
            set
            {
                _auto = value;
                _manager.OnEvent?.Invoke(_manager, SEventType.EnginePauseChanged);
            }
        }
        bool _terminated = false;
        /// <summary>
        /// 状态转移的增加停留时长ms，用于方便调试过程中观察
        /// </summary>
        double _stateChangeDelay = 0;
        SManager _manager;
        /// <summary>
        /// 所有状态对象开始扫描事件
        /// </summary>
        //public EventHandler OnBeginStatesHandle;
        public SEngine(SManager sManager, bool auto)
        {
            _manager = sManager;
            _thread = new Thread(ManagerThreadProc);
            _thread.IsBackground = true;
            Auto = auto;
            _thread.Start();
        }
        //private Dictionary<SInfo, ScriptThread> ComThreads = new Dictionary<SInfo, ScriptThread>();
        /// <summary>
        /// 管理线程函数
        /// </summary>
        internal void ManagerThreadProc()
        {
            while (true)
            {
                //Log("实例1", "sleep...");

                //没差别
                //Thread.Sleep(1);
                SpinWait.SpinUntil(() => false, 1);

                //强制占用CPU
                //Stopwatch sw = Stopwatch.StartNew();
                //while (sw.ElapsedMilliseconds < 1)
                //{
                //    Thread.SpinWait(5000);
                //    Log("实例1", "SpinWait...");
                //}

                //Log("实例1", "sleep...ok");
                if (_terminated)
                    break;

                LoopAction();
            }

            DateTime t1 = DateTime.Now;
            int waitTiems = 3;
            while (true)
            {
                string[] workings = _manager._SInfos.Values.Where(s => s.Working).Select(s => s.Name).ToArray();
                if (workings.Count() == 0)
                    break;
                if ((DateTime.Now - t1).TotalSeconds > 5)
                {
                    int maxCount, availableCount, portCount;
                    ThreadPool.GetMaxThreads(out maxCount, out portCount);
                    ThreadPool.GetAvailableThreads(out availableCount, out portCount);
                    _manager.SystemLog($"停止时等待任务池清零已超过5秒，线程池数：{maxCount},可用线程数:{availableCount},运行中{workings.Count()}：[{string.Join(",", workings)}]");
                    t1 = DateTime.Now;
                    waitTiems--;
                    if (waitTiems <= 0)
                    {
                        _manager.SystemLog($"不再等待任务池，开始执行StateUInit()");
                        break;
                    }
                }

                Thread.Sleep(100);

            }
        }
        void LoopAction()
        {
            //if (OnBeginStatesHandle != null) OnBeginStatesHandle.Invoke(this, null);
            if (!Auto) return;
            lock (_manager.lock_SInfos)
            {
                //Log("实例1", "for...");
                foreach (SInfo si in _manager._SInfos.Values)
                {
                    if (!Auto) return;
                    if (si.Auto && !si.Working && si.Initialized)
                    {
                        if (si.TheResetState != null)
                        {
                            si.NextCheckTime = DateTime.Now;
                            si.NextState = si.TheResetState;
                            si.TheResetState = null;
                        }
                        if (si.NextCheckTime <= DateTime.Now)
                        {
                            si.Working = true;
                            si.EngineStep = "派发";
                            if (si.NextState != null && si.NextState != si.State)
                            {
                                si.LastState = si.State;
                                si.State = si.NextState;
                                si.NextState = null;
                            }
                            if (si.NextStatus != null)
                            {
                                si.Status = si.NextStatus;
                                si.NextStatus = null;
                            }
                            else
                            {
                                si.Status = "";
                                si.NextStatus = null;
                            }
                            ThreadPool.QueueUserWorkItem(new WaitCallback(DoW), si);
                        }
                    }
                }

            }
            //Log("实例1", "for...ok");
            return;
        }
        /// <summary>
        /// 执行任务片段
        /// </summary>
        /// <param name="obj"></param>
        private void DoW(object obj)
        {
            SInfo si = obj as SInfo;
            try
            {
                si.EngineStep = "执行中";
                si.NextCheckTime = DateTime.Now.AddMilliseconds(0);
                (si.Object as IState).StateHandle(si);
                si.NextCheckTime = si.NextCheckTime.AddMilliseconds(_stateChangeDelay);
            }
            catch (Exception E)
            {
                _manager.SystemLog(Text: string.Format("未处理的异常：实例：[{0}]，状态：{1}，信息：{2}", si.Name, si.State, E.Message));
                si.Status = string.Format("未处理的异常：{0}", E.Message);
                si.RepeatState(30000, "");
            }
            finally
            {
                si.EngineStep = "";
                si.Working = false;
            }
        }

        public void UnloadDomain(string Name)
        {
            //GC.Collect();
            AppDomain.Unload(_manager.GetDomain(Name));
            //Domains.Remove(Name);
            //Domains[Name] = null;
        }

        public void Dispose()
        {
            _terminated = true;
            Auto = false;

            _thread.Join();
        }
    }

}
